pub mod lsh;
pub mod jump;
pub mod error;
pub mod stream;
pub mod treeless;
pub mod compressed;

pub use lsh::*;
pub use jump::*;
pub use error::*;
pub use treeless::*;
pub use compressed::*;

use crate::{byte::*, workspace::WorkSpace};

#[derive(Debug)]
pub struct LiteralSection {
    header:LiteralSectionHeader,
    inner:LiteralSectionInner,
}

impl LiteralSection {
    pub fn serialize_into<W:ByteWrite>(&self, writer:&mut ByteWriter<W>) -> LitResult<()> {
        self.header.serialize_into(writer)?;
        self.inner.serialize_into(writer)?;
        Ok(())
    }

    pub fn deserialize_from<R:ByteRead>(total_len:&mut u32, reader:&mut ByteReader<R>, workspace:&mut WorkSpace) -> LitResult<Self> {
        let header = LiteralSectionHeader::deserialize_from(total_len, reader)?;
        let content_size = header.literal_section_content_size();
        let mut content = vec![0;content_size as usize];
        reader.read_to_bytes(&mut content)?;
        let inner = LiteralSectionInner::deserialize_from(&header, content, workspace)?;
        *total_len -= content_size;
        Ok(Self { header, inner })
    }
    
    pub fn literal_stream(&self) -> &[u8] {
        self.inner.literal_stream()
    }
}

#[derive(Debug)]
pub enum LiteralSectionInner {
    RawLiteralsBlock(Vec<u8>),
    RLELiteralsBlock(Vec<u8>),
    CompressedLiteralsBlock(CompressedLiteralsBlock),
    TreelessLiteralsBlock(TreelessLiteralsBlock),
}

impl LiteralSectionInner {
    pub fn serialize_into<W:ByteWrite>(&self, writer:&mut ByteWriter<W>) -> LitResult<()> {
        match self {
            Self::RawLiteralsBlock(raw) => Ok(writer.write_from_bytes(raw)?),
            Self::RLELiteralsBlock(origin) => Ok(writer.write_from_u8(origin[0])?),
            Self::CompressedLiteralsBlock(lb) => Ok(lb.serialize_into(writer)?),
            Self::TreelessLiteralsBlock(lb) => Ok(lb.serialize_into(writer)?),
        }
    }

    pub fn deserialize_from(header:&LiteralSectionHeader, raw_data:Vec<u8>, workspace:&mut WorkSpace) -> LitResult<Self> {
        match header.literals_block_type() {
            LiteralsBlockType::RawLiteralsBlock 
                => { Ok(Self::RawLiteralsBlock(raw_data)) }
            LiteralsBlockType::RLELiteralsBlock 
                => { assert_eq!(raw_data.len(), 1); Ok(Self::RLELiteralsBlock(vec![raw_data[0];header.generated_size() as usize])) },
            LiteralsBlockType::CompressedLiteralsBlock
                => { Ok(Self::CompressedLiteralsBlock(CompressedLiteralsBlock::deserialize_from(header, raw_data, workspace)?)) },
            LiteralsBlockType::TreelessLiteralsBlock
                => { Ok(Self::TreelessLiteralsBlock(TreelessLiteralsBlock::deserialize_from(header, raw_data, workspace)?)) },
        }
    }

    pub fn literal_stream(&self) -> &[u8] {
        match self {
            Self::RawLiteralsBlock(raw) => &raw,
            Self::RLELiteralsBlock(origin) => &origin,
            Self::CompressedLiteralsBlock(lb) => lb.literal_stream(),
            Self::TreelessLiteralsBlock(lb) => lb.literal_stream(),
        }
    }
}